package apibasej.basic.misc;

import apibasej.basic.exception.APIBaseException;
import apibasej.basic.misc.standalone.UtilString;

/**
 * http://code.google.com/p/apibasej/
 * 
 * @author Julio Azevedo Lessa - apibasej@gmail.com
 * 
 */
public class UtilCpfCnpj {

	
	public static String formatCPF(String cpf, boolean validateDV) throws APIBaseException{
		if(cpf==null){
			return null;
		}
		cpf = UtilString.onlyDigits(cpf);
		if(cpf.length()!=11){
			throw new APIBaseException("CPF deve ter 11 dígitos numéricos para ser formatado. CPF: "+cpf);
		}
		if(validateDV && !isCPF(cpf)){
			throw new APIBaseException("Dígito verificador do CPF não confere. CPF: "+cpf);
		}
		StringBuilder sb = new StringBuilder(cpf);
		//01234567890123
		//000.000.000-00
		sb.insert(3, '.');
		sb.insert(7, '.');
		sb.insert(11,'-');
		return sb.toString();
	}
	
	public static String formatCNPJ(String cnpj, boolean validateDV) throws APIBaseException{
		return formatCNPJ(cnpj, validateDV, false);
	}
	public static String formatCNPJ(String cnpj, boolean validateDV, boolean completaDV) throws APIBaseException{
		if(cnpj==null){
			return null;
		}
		cnpj = UtilString.onlyDigits(cnpj);
		if(completaDV && cnpj.length()==12){
			cnpj += getDigDvCnpj(cnpj);
		}
		if(completaDV && cnpj.length()==13){
			cnpj += getDigDvCnpj(cnpj.substring(0,13));
		}
		if(cnpj.length()!=14){
			throw new APIBaseException("CNPJ deve ter 14 dígitos numéricos para ser formatado. CNPJ: "+cnpj);
		}
		if(validateDV && !isCNPJ(cnpj)){
			throw new APIBaseException("Dígito verificador do CNPJ não confere. CNPJ: "+cnpj);
		}
		StringBuilder sb = new StringBuilder(cnpj);
		//012345678901234567
		//00.000.000/0000-00
		sb.insert(2, '.');
		sb.insert(6, '.');
		sb.insert(10,'/');
		sb.insert(15,'-');
		return sb.toString();
	}
	
	public static boolean isCPF(String cpf){ //http://www.devmedia.com.br/validando-o-cpf-em-uma-aplicacao-java/22097
		if(cpf==null){
			return false;
		}
		cpf = UtilString.onlyDigits(cpf);
		return cpf.length()==11 &&
				!UtilString.isAllCharsEquals(cpf) &&
				Character.digit(cpf.charAt(9), 10)==getDigDvCpf(cpf.substring(0,9)) &&
				Character.digit(cpf.charAt(10), 10)==getDigDvCpf(cpf.substring(0,10));
	}
	private static int getDigDvCpf(String trechoIniCpf){
		int somaComPesos = 0;
		int peso = trechoIniCpf.length()+1;
		for(char c : trechoIniCpf.toCharArray()){
			somaComPesos += Character.digit(c, 10)*peso;
			peso--;
		}
		int dv = 11 - (somaComPesos % 11);
		return dv>9?0:dv; //se o DV calculado for 10 ou 11, o dígito verificador será 0; nos outros casos, o dígito verificador é o próprio resto.
	}
	
	
	public static boolean isCNPJ(String cnpj){ //http://www.devmedia.com.br/validando-o-cnpj-em-uma-aplicacao-java/22374
		if(cnpj==null){
			return false;
		}
		cnpj = UtilString.onlyDigits(cnpj);
		return cnpj.length()==14 &&
				!UtilString.isAllCharsEquals(cnpj) &&
				Character.digit(cnpj.charAt(12), 10)==getDigDvCnpj(cnpj.substring(0,12)) &&
				Character.digit(cnpj.charAt(13), 10)==getDigDvCnpj(cnpj.substring(0,13));
	}
	private static int getDigDvCnpj(String trechoIniCnpj){
		int somaComPesos = 0;
		int peso = trechoIniCnpj.length()-7;
		for(char c : trechoIniCnpj.toCharArray()){
			somaComPesos += Character.digit(c, 10)*peso;
			peso--;
			if(peso<2){// se for menor que 2 define o peso 9 e vai diminuindo novamente
				peso = 9;
			}
		}
		int dv = 11 - (somaComPesos % 11);
		return dv>9?0:dv; //se o DV calculado for 0 ou 1, o dígito verificador será 0; nos outros casos, o dígito verificador é o próprio resto.
	}
	
}
